package org.ossreviewtoolkit.clients.cvemanager

import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json

import okhttp3.Credentials
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient

import retrofit2.Retrofit
import retrofit2.http.Body
import retrofit2.http.POST

/**
 * Interface for the CVE Manager REST API.
 */
interface CveManagerService {
    companion object {
        /**
         * The default base URL for the REST API of the CVE Manager service.
         */
        const val DEFAULT_BASE_URL = "http://sbom.test.osinfra.cn/"

        /**
         * The JSON (de-)serialization object used by this service.
         */
        val JSON = Json.Default

        /**
         * Create an CVE Manager service instance for communicating with a server running at the given [url], optionally
         * using [user] and [password] for basic authentication, and / or a pre-built OkHttp [client].
         */
        fun create(
            url: String,
            user: String? = null,
            password: String? = null,
            client: OkHttpClient? = null
        ): CveManagerService {
            val cveManagerClient = (client ?: OkHttpClient()).newBuilder()
                .addInterceptor { chain ->
                    val request = chain.request()
                    val requestBuilder = request.newBuilder()

                    if (user != null && password != null) {
                        requestBuilder.header("Authorization", Credentials.basic(user, password))
                    }

                    chain.proceed(requestBuilder.build())
                }
                .build()

            val contentType = "application/json".toMediaType()
            val retrofit = Retrofit.Builder()
                .client(cveManagerClient)
                .baseUrl(url)
                .addConverterFactory(JSON.asConverterFactory(contentType))
                .build()

            return retrofit.create(CveManagerService::class.java)
        }
    }

    @Serializable
    data class ComponentReportRequest(
        val coordinates: List<String>
    )

    @Serializable
    data class ComponentReport(
        /** The HTTP status code. */
        val code: Int,

        /** The message of the response. */
        val message: String? = null,

        /** The number of vulnerabilities. */
        val count: Int,

        /** The list of known vulnerabilities. */
        val data: List<Vulnerability>
    )

    @Serializable
    data class Vulnerability(
        /** The cve number. */
        @SerialName("cve_num")
        val cveNum: String,

        /** The owned component name. */
        @SerialName("owned_component")
        val ownedComponent: String,

        /** The version of the component. */
        val version: String,

        /** The issue id. */
        @SerialName("issue_id")
        val issueId: Int,

        /** The issue status. */
        @SerialName("issue_status")
        val issueStatus: Int,

        /** The cvss2 score of the vulnerability. */
        @SerialName("cvss2_score")
        val cvss2Score: Float,

        /** The cvss2 vector of the vulnerability. */
        @SerialName("cvss2_vector")
        val cvss2Vector: String? = null,

        /** The cvss3 score of the vulnerability. */
        @SerialName("cvss3_score")
        val cvss3Score: Float,

        /** The cvss3 vector of the vulnerability. */
        @SerialName("cvss3_vector")
        val cvss3Vector: String? = null,

        /** The owner of the component. */
        val owner: String,

        /** The reference URL of the vulnerability. */
        @SerialName("cve_url")
        val cveUrl: String,

        /** The Package URL. */
        val purl: String
    )

    /**
     * Request vulnerability reports for [components].
     */
    @POST("api/v1/component-report")
    suspend fun getComponentReport(@Body components: ComponentReportRequest): ComponentReport
}
